import { cloneDeep } from 'lodash-es'
import { storeToRefs } from 'pinia'
import { useTagCacheStoreWithOut } from '@/store/modules/tag'
import { useUserStoreWithOut } from '@/store/modules/user'
import remainingRouter from '@/router/remaining'
import router from '@/router/index'
import { SystemMenuTypeEnum } from '@/enums/systemEnums'
const routeComponentList = import.meta.glob('/src/views/**/**.vue')
export const Layout = () => import('@/layout/Layout.vue')
// 路由白名单
export const routerWhiteList = {
  login: ['Login', 'SSOLogin', 'SocialLogin', 'Exception403', 'Exception404', 'Exception500', 'NetworkError', 'Developmenting', 'UpgradeRepair', 'Redirect'], // 登录白名单
  multipleTag: ['SingleParamDetail', 'TagDetail', 'MultiParamsDetail', 'QueryDetail'], // 多标签页白名单
  root: ['PageDesign', 'DesignerPreview', 'PreviewFrame', 'BigScreen', 'BigScreenWorkstation', 'BigScreenPreview'], // 根路由白名单
  rootLayout: ['SystemMyNotify'] // 需要放在 layout 根路由下的路由白名单（其菜单层级关系不变，只是面包屑不需要展示上级）
}

// ---------------------------------------------- 路由处理相关

/**
 * 路由实例化只需要将菜单类型的数据转化，目录类型的数据无需转化
 * @param routeList 后端接口返回的用户权限菜单数据
 * @param permitList 后端接口返回的用户权限操作数据
 * @returns 需要动态实例化的路由数据
 */
export const getPermitRoutes = (dynamicPermitRoutes, localPermitRoutes) => {
  let arr: any = []
  if (dynamicPermitRoutes.length > 0) {
    if (localPermitRoutes.length > 0) {
      arr = dynamicPermitRoutes.concat(...localPermitRoutes)
    } else {
      arr = dynamicPermitRoutes
    }
  } else {
    if (localPermitRoutes.length > 0) {
      arr = localPermitRoutes
    }
  }
  if (arr.length > 0) {
    arr.forEach(item => {
      if (item.meta.isFixed) {
        initFixedTagToAllTag(item)
      }
    })
    return arr
  } else {
    return []
  }
}

/**
 * 初始化时将系统固定标签加入到标签栏
 * 固定标签缓存规则：系统确定的固定标签，不缓存在fixedTagList中，只有用户设置的固定标签需要被缓存，两者固定后，其数据字段isFixed均为true
 * 通过判断isFixed字段为true，以及是否缓存在fixedTagList中，来判断是系统固定标签，还是用户固定标签
 **/
const initFixedTagToAllTag = (tabRouter: any) => {
  const tagCacheStore = useTagCacheStoreWithOut()
  tagCacheStore.getAllTagCache()
  const { tagList } = storeToRefs(tagCacheStore)
  const userStore = useUserStoreWithOut()
  const { menus } = storeToRefs(userStore)
  const menu = findMenuById(menus.value, tabRouter.meta.id as number | string)
  // 获取被缓存的标签页数据，判断当前路由是否已打开
  const hasValue = tagList.value.some((item: any) => {
    return item.path === tabRouter.path
  })
  const tagRoute: any = {
    path: '',
    name: '',
    meta: {}
  }
  tagRoute.path = tabRouter.path
  tagRoute.name = tabRouter.name
  tagRoute.meta = tabRouter.meta
  tagRoute.meta.breadcrumb = menu.meta.breadcrumb
  // 标签缓存中已存在当前路由，则更新路由的 meta 信息
  if (hasValue) {
    tagCacheStore.updateTagMeta({ value: tagRoute })
  } else {
    // 标签缓存中不存在当前路由，判断当前路由是否需要在标签栏显示，如需要则添加到标签缓存中，showTag:0 表示不在标签栏显示，否则需要在标签栏显示
    if (tabRouter.meta.showTag) {
      tagCacheStore.tagOperateHandle({ mode: 'push', value: tagRoute })
    }
  }
}

// 初始化路由
export const initRouter = async () => {
  const userStore = useUserStoreWithOut()
  const { routerList, menus } = storeToRefs(userStore)
  return new Promise(async resolve => {
    if (routerList.value.length > 0) {
      let rootLayout = {
        path: '/',
        name: 'Layout',
        component: Layout,
        redirect: getLayoutRedirect(menus.value),
        children: [],
        meta: {
          sort: 0,
          visible: false,
          type: '1',
          showTag: 0,
          isRoot: true
        }
      }
      router.addRoute(rootLayout)
      router.options.routes = router.options.routes.concat(rootLayout)
      routerList.value?.map((v: any, idx) => {
        if (v.meta.isRoot) {
          // 防止重复添加路由
          if (router.options.routes.findIndex(value => value.path === v.path) !== -1) {
            return
          } else {
            if (!router.hasRoute(v?.name)) router.addRoute(v)
            router.options.routes = router.options.routes.concat(v)
          }
        } else {
          const index = router.options.routes.findIndex(v => v.name === 'Layout')
          // 防止重复添加路由
          if (router.options.routes[index].children?.findIndex(value => value.path === v.path) !== -1) {
            return
          } else {
            if (!router.hasRoute(v?.name)) router.addRoute('Layout', v)
            router.options.routes[index].children.splice(idx, 0, v)
          }
        }
      })
    }
    // 404匹配规则需在最后加入到路由实例中
    const noFound = { path: '/:pathMatch(.*)', redirect: '/404', name: '404' }
    router.addRoute(noFound)
    router.options.routes = router.options.routes.concat(noFound)
    resolve(router)
  })
}

// 获取 Layout 框架层的默认重定向路由
export const getLayoutRedirect = (list: any) => {
  if (list.length > 0) {
    if (list[0].meta.type === SystemMenuTypeEnum.DIR) {
      return list[0].redirect
    } else {
      return list[0].path
    }
  } else {
    return '/404'
  }
}

// ---------------------------------------------- 菜单处理相关

/**
 * 路由实例化只需要将菜单类型的数据转化，目录类型的数据无需转化
 * @param routeList 后端接口返回的用户权限菜单数据
 * @param permitList 后端接口返回的用户权限操作数据
 * @returns 需要动态实例化的路由数据
 */
export const getPermitMenus = (dynamicPermitMenus, localPermitMenus) => {
  let arr: any = []
  if (dynamicPermitMenus.length > 0) {
    if (localPermitMenus.length > 0) {
      arr = dynamicPermitMenus.concat(...localPermitMenus)
    } else {
      arr = dynamicPermitMenus
    }
  } else {
    if (localPermitMenus.length > 0) {
      arr = localPermitMenus
    }
  }
  return arr
}

// 菜单原始数据格式化
export const permitMenuFormat = data => {
  if (data.length > 0) {
    // 将路由转为树形结构，在 meta 中添加面包屑字段，为后续面包屑获取使用
    const treeMenus = menuToTree(data)
    // 删除无子级菜单层路由的目录层菜单，这种目录层菜单不应该被显示
    removeEmptyCatalog(treeMenus)
    // 数据排序
    // 重置各目录层的重定向
    resetRedirect(treeToAscending(treeMenus))
    // 设置面包屑数据
    breadcrumbFormat(treeMenus)
    return treeMenus
  } else {
    return []
  }
}

// 侧边显示的菜单数据格式化
export const sidebarMenuFormat = data => {
  if (data.length > 0) {
    const treeMenus = menuToTree(data)
    // 删除无子级菜单层路由的目录层菜单，这种目录层菜单不应该被显示
    removeEmptyCatalog(treeMenus)
    // 数据排序
    return treeToAscending(treeMenus)
  } else {
    return []
  }
}

// 过滤掉 meta 中 visible 为 false 的数据，菜单只需要侧边可显示的数据
export const filterVisibleStatusMenu = (data: any) => {
  return data.filter((v: any) => v.meta.visible)
}

// 将规范路由的一维数组转为树形结构
export const menuToTree = (arrRoutes: any) => {
  const parents = arrRoutes.filter(function (item: any) {
    return item.meta.parentId === 0
  })
  const children = arrRoutes.filter(function (item: any) {
    return item.meta.parentId !== 0
  })
  if (parents.length > 0 && children.length > 0) {
    const convert = (parents: any, children: any) => {
      parents.forEach(function (item: any) {
        item.children = []
        children.forEach(function (current: any, index: any) {
          if (current.meta.parentId === item.meta.id) {
            const temp = children.filter(function (_v: any, idx: any) {
              return idx !== index
            })
            item.children.push(current)
            convert([current], temp) // 递归
          }
        })
      })
    }
    // 递归处理动态路由层级
    convert(parents, children)
    return parents
  } else {
    return parents
  }
}

// 递归添加面包屑数据
export const breadcrumbFormat = (tree: any) => {
  tree.forEach(function (item: any) {
    if (!item.meta.breadcrumb) {
      item.meta.breadcrumb = []
      const currentBreadcrumb = cloneDeep(item)
      currentBreadcrumb.children = []
      item.meta.breadcrumb.push(currentBreadcrumb)
    }
    const convert = (parent, children) => {
      children.forEach((current: any) => {
        current.meta.breadcrumb = cloneDeep(parent.meta.breadcrumb)
        const currentSubBreadcrumb = cloneDeep(current)
        currentSubBreadcrumb.meta.breadcrumb = []
        currentSubBreadcrumb.children = []
        current.meta.breadcrumb.push(currentSubBreadcrumb)
        if (current.children && current.children.length > 0) {
          convert(current, current.children) // 递归
        }
      })
    }
    if (item.children && item.children.length > 0) {
      convert(item, item.children)
    }
  })
}

// 删除空的目录层
export const removeEmptyCatalog = treeData => {
  const traversal = data => {
    for (let i = 0; i < data.length; i++) {
      const info = data[i]
      if (info.children) {
        if (info.children.length > 0) {
          traversal(info.children)
        }
        if (info.children.length === 0 && info.meta.type === SystemMenuTypeEnum.DIR) {
          const index = data.findIndex(item => info.meta.id === item.meta.id)
          data.splice(index, 1)
          i--
        }
      }
    }
  }
  traversal(treeData)
}

// 树形结构数据递归排序
export const treeToAscending = (arr: any) => {
  const ascending = (arr: any) => {
    return arr.sort((a: any, b: any) => {
      return a?.meta?.sort - b?.meta?.sort
    })
  }
  const newTree = ascending(arr)
  newTree.forEach(function (item: any) {
    if (item.children && item.children.length > 1) {
      item.children = treeToAscending(item.children)
    }
  })
  return newTree
}

// 重置目录层的重定向
export const resetRedirect = data => {
  data.forEach(item => {
    if (item.meta.type === SystemMenuTypeEnum.DIR) {
      // 此时目录层的children肯定有子级，因为上面已经把无子级的目录层删除
      item.redirect = getRedirect(item.path, item.meta.type, item.children)
      resetRedirect(item.children)
    }
  })
}

export const getRedirect = (parentPath: string, parentType: number, children) => {
  // 目录层重定向只定向到目录层的下一层菜单层，菜单层如果还有子级菜单，则不再向下递归寻找重定向
  if (!children || children.length == 0 || (children.length > 0 && parentType === 2)) {
    return parentPath
  }
  // 递归子节点
  if (children[0].children) return getRedirect(children[0].path, children[0].meta.type, children[0].children)
}

// ---------------------------------------------- 路由、菜单处理的公共方法

// 后端字段转化为前端字段
export const dataFieldInvert = (data, isMenu) => {
  const { VITE_DEV } = import.meta.env
  const result: any = []
  data.forEach(item => {
    const itemMenu = {
      id: item.id,
      parentId: item.parentId,
      title: item.title,
      icon: item.icon,
      component: item.component,
      path: item.path,
      visible: item.visible,
      sort: item.sort,
      name: item.name,
      permit: item.permit,
      transitionName: item.transitionName,
      keepAlive: item.keepAlive,
      isFixed: item.isFixed,
      type: item.type,
      badge: item.badge,
      dot: item.dot,
      status: item.status,
      isDev: item.isDev
    }
    if ((itemMenu.isDev && VITE_DEV === 'true') || !itemMenu.isDev) {
      result.push(dataToRouteMenu(itemMenu, isMenu))
    }
  })
  return result
}

// 菜单数据转化为规范化的路由格式数据
export const dataToRouteMenu = (item, isMenu) => {
  const tagCacheStore = useTagCacheStoreWithOut()
  tagCacheStore.getFixedTagCache()
  const { fixedTagList } = storeToRefs(tagCacheStore)
  let path = ''
  let name = ''
  let component: any = undefined
  let redirect = undefined
  let showTag = 0
  if (item.path.includes('://')) {
    path = '/external-link'
    name = 'ExternalLink'
    redirect = item.path
  } else {
    path = item.path
    name = item.name
    showTag = routerWhiteList.multipleTag.includes(name) ? 9 : routerWhiteList.root.includes(name) ? 0 : 1
  }
  component = isMenu ? undefined : item.component ? routeComponentList[`/src/views${item.component}/index.vue`] : undefined
  return {
    path,
    name,
    redirect,
    component,
    meta: {
      id: item.id,
      parentId: item.parentId,
      icon: item.icon,
      title: item.title,
      keepAlive: item.keepAlive,
      isFixed: fixedTagList.value && fixedTagList.value.includes(path) ? true : item.isFixed,
      dot: item.dot,
      sort: item.sort,
      transitionName: item.transitionName,
      type: item.type,
      visible: item.visible,
      badge: item.badge,
      status: item.status,
      showTag,
      isRoot: !!routerWhiteList.root.includes(name),
      permit: item.permit
    }
  }
}

// 过滤掉目录类型，只保留菜单类型数据，供路由实例化使用
export const filterMenuTypeRoute = data => {
  if (data && data.length > 0) {
    return data.filter(item => {
      return item.meta.type === SystemMenuTypeEnum.MENU
    })
  } else {
    return []
  }
}

// 本地路由数据根据 permitList 进行过滤，保留 permitList 中包含的，以及无需权限验证的本地路由数据
export const filterLocalPermitData = (permitList, localPermitRoutes) => {
  const result: any = []
  if (localPermitRoutes.length > 0) {
    if (permitList && permitList.length > 0) {
      localPermitRoutes.forEach((item: any) => {
        if (!item.meta.permit) {
          result.push(item)
        } else {
          const index = permitList.findIndex(v => v === item.meta.permit)
          if (index >= 0) {
            result.push(item)
          }
        }
      })
    } else {
      localPermitRoutes.forEach((item: any) => {
        if (!item.meta.permit) {
          result.push(item)
        }
      })
    }
  }
  return result
}

// 根据路由 id 递归寻找指定的菜单数据
export const findMenuById = (tree, id) => {
  let currentMenu: any = null
  const findMenu = (arr: object[], id) => {
    arr.forEach((arrItem: any) => {
      if (arrItem.meta.id === id) {
        currentMenu = cloneDeep(arrItem)
        return
      } else {
        if (arrItem.children && arrItem.children.length > 0) {
          findMenu(arrItem.children, id)
        }
      }
    })
  }
  findMenu(tree, id)
  return currentMenu
}

/**
 * 设置页面标题
 */
export const setPageTitle = meta => {
  const { t } = useI18n() // 国际化
  if (meta.title) {
    document.title = t('router', meta.title) + ' - ' + t('common', 'title')
  } else {
    document.title = t('common', 'title')
  }
}

// 退出登录后重置路由
export const resetRouter = () => {
  const nameArr: any = []
  remainingRouter.forEach(item => {
    nameArr.push(item.name)
  })
  router.getRoutes().forEach(route => {
    const { name } = route
    if (name && !nameArr.includes(name)) {
      router.hasRoute(name) && router.removeRoute(name)
    }
  })
  router.options.routes = remainingRouter
}

// 路由参数处理
export const parseURL = (url: string | null | undefined): { basePath: string; paramsObject: { [key: string]: string } } => {
  // 如果输入为 null 或 undefined，返回空字符串和空对象
  if (url == null) {
    return { basePath: '', paramsObject: {} }
  }

  // 找到问号 (?) 的位置，它之前是基础路径，之后是查询参数
  const questionMarkIndex = url.indexOf('?')
  let basePath = url
  const paramsObject: { [key: string]: string } = {}

  // 如果找到了问号，说明有查询参数
  if (questionMarkIndex !== -1) {
    // 获取 basePath
    basePath = url.substring(0, questionMarkIndex)

    // 从 URL 中获取查询字符串部分
    const queryString = url.substring(questionMarkIndex + 1)

    // 使用 URLSearchParams 遍历参数
    const searchParams = new URLSearchParams(queryString)
    searchParams.forEach((value, key) => {
      // 封装进 paramsObject 对象
      paramsObject[key] = value
    })
  }

  // 返回 basePath 和 paramsObject
  return { basePath, paramsObject }
}

// 获取当前菜单的根级菜单
export const getCurrentRootMenu = route => {
  const userStore = useUserStoreWithOut()
  const { menus } = storeToRefs(userStore)
  const menu = findMenuById(menus.value, route.meta.id as number | string)
  let rootMenu = null
  // 根据面包屑导航找到当前路由的根路由
  if (menu.meta.breadcrumb && (menu.meta.breadcrumb as any).length > 0) {
    rootMenu = menu.meta.breadcrumb[0]
  } else {
    rootMenu = menu
  }
  return rootMenu
}

// 获取当前菜单的根级菜单的所有子级菜单
export const getCurrentRootMenuChildren = (menuData, route) => {
  const rootMenu: any = getCurrentRootMenu(route)
  let currentMenuList: any = []
  const recursionMenuData = menuData => {
    for (let i = 0; i < menuData.length; i++) {
      if (menuData[i].meta.id === rootMenu.meta.id) {
        if (menuData[i].children && menuData[i].children.length > 0) {
          currentMenuList = menuData[i].children
        } else {
          // 如果当前路由没有子级数据，将自己返回显示在侧边栏
          currentMenuList = [menuData[i]]
        }
        // 使用for循环，提升代码性能，找到即终止循环
        break
      } else {
        if (menuData[i].children && menuData[i].children.length > 0) {
          recursionMenuData(menuData[i].children)
        }
      }
    }
  }
  if (rootMenu) {
    recursionMenuData(menuData)
  }
  return currentMenuList
}

// 获取当前菜单父级的所有子级
export const getCurrentMenuParentChildren = (menuData, menu) => {
  let currentMenuList = []
  const recursionMenuData = menuData => {
    for (let i = 0; i < menuData.length; i++) {
      if (menuData[i].meta.id === menu.meta.parentId) {
        if (menuData[i].children && menuData[i].children.length > 0) {
          currentMenuList = menuData[i].children
        }
        break
      } else {
        if (menuData[i].children && menuData[i].children.length > 0) {
          recursionMenuData(menuData[i].children)
        }
      }
    }
  }
  recursionMenuData(menuData)
  return currentMenuList
}

// 判断当前根菜单是否有子级
export const hasChildrenMenuFn = (menuData, menu) => {
  const rootMenu: any = getCurrentRootMenu(menu)
  let hasChildren = false
  for (let i = 0; i < menuData.length; i++) {
    if (menuData[i].meta.id === rootMenu.meta.id) {
      if (menuData[i].children && menuData[i].children.length > 0) {
        hasChildren = true
      } else {
        hasChildren = false
      }
    }
  }
  return hasChildren
}
